package com.bestcem.xm.member.handler.export;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.EnumUtil;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.label.entity.pojo.LabelValueDO;
import com.bestcem.xm.member.config.FileConfig;
import com.bestcem.xm.member.controller.v2.param.FilterMembersParam;
import com.bestcem.xm.member.dao.DisplayRangeDao;
import com.bestcem.xm.member.dao.ExportRecordDao;
import com.bestcem.xm.member.dao.ExtendFieldDao;
import com.bestcem.xm.member.entity.mongo.ExtendFieldValue;
import com.bestcem.xm.member.entity.mysql.LabelValueId;
import com.bestcem.xm.member.entity.pojo.ExportRecordDO;
import com.bestcem.xm.member.entity.pojo.ExtendFieldDO;
import com.bestcem.xm.member.enums.ExportStatusEnum;
import com.bestcem.xm.member.enums.ExtendFieldTypeEnum;
import com.bestcem.xm.member.enums.MemberTypeEnum;
import com.bestcem.xm.member.grpc.client.XmMemberClient;
import com.bestcem.xm.member.service.DisplayRangeService;
import com.bestcem.xm.member.util.CheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.bestcem.xm.member.constant.Constants.*;

/**
 * 示例服务
 *
 * @author yf.wang <yf.wang@idiaoyan.com>
 * @version V1.0
 * @date 2021/8/2
 */
@Slf4j
public abstract class BaseExportHandle {

    @Resource
    protected ExportRecordDao exportRecordDao;

    @Resource
    protected ExtendFieldDao extendFieldDao;

    @Resource
    protected RedisService redisService;

    /*@Resource
    protected OssService ossService;*/
    @Autowired
    private StorageService storageService;

    @Resource
    protected DisplayRangeService displayRangeService;

    @Autowired
    private FileConfig fileConfig;

    @Resource
    private DisplayRangeDao displayRangeDao;

    @Resource
    protected XmMemberClient xmMemberClient;

    /**
     * 导出联系人
     *
     * @param context
     */
    public void exportMember(ExportContext context) {
        // 检查用户是否有查看联系方式的权限
        boolean mDisplay = this.displayRangeService.isDisplayContact(context.getOrgId(), context.getMType(), context.getOpUserId());
        context.setIsMDisplay(mDisplay);
        // 获取文件名称
        String fileName = EnumUtil.getEnumByIndex(MemberTypeEnum.class, context.getMType()).getName() + "-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".xlsx";
        String tempFilePath = fileConfig.getMemberTempFilePath(fileName);
        context.setFileName(tempFilePath);
        // 导出数据到指定文件
        ServiceResult<File> fileServiceResult = exportToExcel(context);
        if (fileServiceResult.isSuccess()) {
            File file = fileServiceResult.getData();
            // 获取文件大小
            long length = file.length();
            // 上传oos
            //String ossUrl = ossService.uploadSimpleFile(file, fileName, OssPathEnum.TEMP_MEMBER, 0, tempFilePath, "导出联系人数据");
            String ossUrl = storageService.upload(file, fileName, OssPathEnum.TEMP_MEMBER.getPath(), new Dict()).getUrl();
            if (log.isInfoEnabled()) {
                log.info("导出联系人数据,url:{}", ossUrl);
                log.info("文件大小 {}", length);
            }
            // 删除临时文件
            file.delete();
            // 设置进度条为100%
            setProgressBarStatus(context.getExportRecordId(), context.getMemberCount(), context.getMemberCount());
            // 计算文件大小
            String size = NumberUtil.round(length / 1024.0, 2) + "k";
            if (log.isInfoEnabled()) {
                log.info("文件大小 {}", size);
            }
            // 完成导出
            finishExport(context.getExportRecordId(), fileName, ossUrl, ExportStatusEnum.SUCCESS.getIndex(), size);
        } else {
            log.error("联系人导出失败 {}", fileServiceResult.getMsg());
        }
    }

    /**
     * 完成导出任务 更新状态
     *
     * @param exportRecordId
     * @param fileName
     * @param path
     * @param status
     * @param size
     */
    private void finishExport(String exportRecordId, String fileName, String path, int status, String size) {
        ExportRecordDO exportRecord = new ExportRecordDO();
        exportRecord.setExportId(exportRecordId);
        exportRecord.setFileName(fileName);
        exportRecord.setFileUrl(path);
        exportRecord.setStatus(status);
        exportRecord.setFileSize(size);
        exportRecordDao.updateStatusAndFile(exportRecord);
    }

    /**
     * 联系人导出
     *
     * @param context
     * @return
     */
    public abstract ServiceResult<File> exportToExcel(ExportContext context);

    /**
     * 更新导出状态
     *
     * @param status
     * @param id
     */
    public void updateExportStatus(int status, String id) {
        ExportRecordDO exportRecord = new ExportRecordDO();
        exportRecord.setExportId(id);
        exportRecord.setStatus(status);
        exportRecordDao.updateStatusById(exportRecord);
    }

    public void setProgressBarStatus(String id, int init, int count) {
        String key = "member:member.export." + id;
        JSONObject object = new JSONObject();
        object.put("complete_count", init);
        object.put("total_count", count);
        object.put("last_timestamp", System.currentTimeMillis());
        redisService.set(key, object.toJSONString());
    }

    public int calcUpdateProgressStep(int memberCount) {
        int per = (int) (memberCount * 0.05);
        return per > 50 ? per : 50;
    }

    /**
     * 获取该组织下相关联系人的所有扩展字段
     *
     * @param orgId
     * @param attribute
     * @return
     */
    public List<ExtendFieldDO> getExtendFields(String orgId, Integer attribute) {
        return extendFieldDao.listMemberExtendField(orgId, attribute);
    }

    /**
     * 转换扩展字段格式
     *
     * @param field
     * @param mdisplay
     * @return
     */
    public String convertFieldValue(ExtendFieldValue field, boolean mdisplay) {

        Object fieldValue = field.getFieldValue();
        Integer fieldType = field.getFieldType();
        if (ObjectUtil.isEmpty(fieldValue)) {
            return "";
        }

        switch (EnumUtil.getEnumByIndex(ExtendFieldTypeEnum.class, fieldType)) {
            case DATETIME:
                return DateUtil.parse(fieldValue.toString()).toString("yyyy/MM/dd");
            case EMAIL:
                String email = String.valueOf(fieldValue);
                if (!mdisplay) {
                    return CheckUtil.hiddenEmail(email);
                }
                return email;
            case MOBILE:
                String mobile = String.valueOf(fieldValue);
                if (!mdisplay) {
                    return CheckUtil.hiddenMobile(mobile);
                }
                return mobile;
            default:
                return String.valueOf(fieldValue);
        }
    }

    /**
     * 构建excel中扩展字段的值
     *
     * @param fieldStr
     * @param isMDisplay
     * @param extendFields
     * @param content
     */
    public void buildExcelField(String fieldStr, Boolean isMDisplay, List<ExtendFieldDO> extendFields,
                                List<String> content) {
        if (CollUtil.isNotEmpty(extendFields)) {
            Map<String, String> fieldMap = new HashMap<>();
            // 扩展字段转换成正确格式的值
            if (StrUtil.isNotEmpty(fieldStr)) {
                List<ExtendFieldValue> fieldValList =
                        JSONArray.parseArray(fieldStr, ExtendFieldValue.class);
                if (CollUtil.isNotEmpty(fieldValList)) {
                    fieldValList.forEach(field -> {
                        String value = convertFieldValue(field, isMDisplay);
                        fieldMap.put(field.getFieldId(), value);
                    });
                }
            }
            for(ExtendFieldDO extendField : extendFields){
                String value = fieldMap.get(extendField.getFieldId());
                if (log.isInfoEnabled()) {
                    log.info("{} {}", extendField.getName(), value);
                }
                if (StrUtil.isBlank(value)) {
                    value = "";
                }
                content.add(value);
            }
        }
    }

    /**
     * 构建excel中标签的值
     *
     * @param labelStr
     * @param labelValueMap
     * @param content
     */
    public void buildExcelLabel(String labelStr, Map<String, List<LabelValueDO>> labelValueMap, List<String> content) {
        Map<String, String> memberLabelMap = new HashMap<>();
        if (StrUtil.isNotEmpty(labelStr)) {
            List<LabelValueId> labels = JSONArray.parseArray(labelStr, LabelValueId.class);
            if (CollUtil.isNotEmpty(labels)) {
                labels.forEach(var -> {
                    memberLabelMap.put(var.getLabelId(), var.getId());
                });
            }
        }
        // 获取联系人标签值id 对应的标签值
        if (CollUtil.isNotEmpty(labelValueMap)) {
            labelValueMap.forEach((k, v) -> {
                if (log.isInfoEnabled()) {
                    log.info("{}", k);
                }
                // 获取第一个标签数据（只是为了获取标签id）
                Optional<LabelValueDO> labelValueOptional = v.stream().findFirst();
                if (labelValueOptional.isPresent()) {
                    LabelValueDO labelValue = labelValueOptional.get();
                    if (memberLabelMap.containsKey(labelValue.getLabelId())) {
                        String labelValueId = memberLabelMap.get(labelValue.getLabelId());
                        // 有该标签的标签值
                        for (LabelValueDO value : v) {
                            if (value.getLabelValueId().equals(labelValueId)) {
                                content.add(value.getValue());
                                break;
                            }
                        }
                    } else {
                        content.add("");
                    }
                }
            });
        }
    }

    /**
     * 获取表头字段
     *
     * @param labelValueMap
     * @param extendFields
     * @param mType
     * @return
     */
    public List<List<String>> getMemberHeader(Map<String, List<LabelValueDO>> labelValueMap, List<ExtendFieldDO> extendFields, Integer mType) {
        List<List<String>> headers = new ArrayList<>();
        switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, mType)) {
            case INDIVIDUAL:
                // 个人联系人
                INDIVIDUAL_EXPORT_BASE_EXCEL_HEADERS.forEach(base -> {
                    List<String> head = new ArrayList<>();
                    head.add(base);
                    headers.add(head);
                });
                break;
            case INSTITUTION:
                // 机构联系人
                INSTITUTION_BASE_EXCEL_HEADERS.forEach(base -> {
                    List<String> head = new ArrayList<>();
                    head.add(base);
                    headers.add(head);
                });
                break;
            case INTERIOR:
                // 内部联系人
                INTERIOR_EXPORT_BASE_EXCEL_HEADERS.forEach(base -> {
                    List<String> head = new ArrayList<>();
                    head.add(base);
                    headers.add(head);
                });
                break;
        }
        for (int i = 0; i < extendFields.size(); i++) {
            List<String> head = new ArrayList<>();
            head.add(extendFields.get(i).getName());
            headers.add(head);
        }
        if (CollUtil.isNotEmpty(labelValueMap)) {
            labelValueMap.keySet().forEach(name -> {
                List<String> head = new ArrayList<>();
                head.add(name);
                headers.add(head);
            });
        }
        return headers;
    }

    /**
     * 获取表头字段
     *
     * @param labelValueMap 标签映射
     * @param extendFields 扩展字段列表
     * @param mType 联系人类型
     * @param headerTypeMap 表头字段映射
     * @return
     */
    public List<List<String>> getMemberHeader(Map<String, List<LabelValueDO>> labelValueMap,
                                              List<ExtendFieldDO> extendFields,
                                              Integer mType,
                                              Map<String, String> headerTypeMap) {
        List<List<String>> headers = new ArrayList<>();
        switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, mType)) {
            case INDIVIDUAL:
                // 个人联系人
                INDIVIDUAL_EXCEL_EXPORT_HEADERS.forEach(base -> {
                    List<String> head = new ArrayList<>();
                    head.add(base);
                    headers.add(head);
                    if (base.equals("出生日期")) {
                        headerTypeMap.put(base, EXCEL_TYPE_DATE);
                    } else if (base.equals("年龄") || base.equals("手机号")) {
                        headerTypeMap.put(base, EXCEL_TYPE_NUMBER);
                    } else {
                        headerTypeMap.put(base, EXCEL_TYPE_STR);
                    }
                });
                break;
            case INSTITUTION:
                // 机构联系人
                INSTITUTION_EXCEL_EXPORT_HEADERS.forEach(base -> {
                    List<String> head = new ArrayList<>();
                    head.add(base);
                    headers.add(head);
                    if (base.equals("手机号")) {
                        headerTypeMap.put(base, EXCEL_TYPE_NUMBER);
                    }
                });
                break;
            case INTERIOR:
                // 内部联系人
                INTERIOR_EXCEL_EXPORT_HEADERS.forEach(base -> {
                    List<String> head = new ArrayList<>();
                    head.add(base);
                    headers.add(head);
                    if (base.equals("出生日期")) {
                        headerTypeMap.put(base, EXCEL_TYPE_DATE);
                    } else if (base.equals("年龄") || base.equals("手机号")) {
                        headerTypeMap.put(base, EXCEL_TYPE_NUMBER);
                    } else {
                        headerTypeMap.put(base, EXCEL_TYPE_STR);
                    }
                });
                break;
        }
        for (int i = 0; i < extendFields.size(); i++) {
            List<String> head = new ArrayList<>();
            ExtendFieldDO extendField = extendFields.get(i);
            head.add(extendField.getName());
            headers.add(head);
            if (ExtendFieldTypeEnum.DATETIME.getIndex() == extendField.getType()) {
                // 日期类型
                headerTypeMap.put(extendField.getName(), EXCEL_TYPE_DATE);
            } else if (ExtendFieldTypeEnum.NUMBER.getIndex() == extendField.getType() ||
                    ExtendFieldTypeEnum.MOBILE.getIndex() == extendField.getType()) {
                // 数字 手机号类型
                headerTypeMap.put(extendField.getName(), EXCEL_TYPE_NUMBER);
            } else {
                // 其他类型
                headerTypeMap.put(extendField.getName(), EXCEL_TYPE_STR);
            }
        }
        if (CollUtil.isNotEmpty(labelValueMap)) {
            labelValueMap.keySet().forEach(name -> {
                List<String> head = new ArrayList<>();
                head.add(name);
                headers.add(head);
            });
        }
        return headers;
    }

    /**
     * 处理问题数据
     *
     * @param address
     */
    public void dealAddress(List<String> address) {
        if (address.size() < 4) {
            int num = 4 - address.size();
            for (int i = 0; i < num; i++) {
                address.add("");
            }
        }
    }

    /**
     * 根据组织id获取该组织下门店名称与id的映射
     *
     * @param orgId
     * @return
     */
    public Map<String, String> getStoreIdNameMap(String orgId) {
        ServiceResult<JSONObject> result = xmMemberClient.getStoreIdNameMap(orgId);
        if (!result.isSuccess()) {

        }
        JSONObject data = result.getData();
        if (!data.isEmpty()) {
            HashMap<String, String> storeIdNameMap = new HashMap<>(data.size());
            data.keySet().forEach(key -> {
                storeIdNameMap.put(key, data.get(key).toString());
            });
            return storeIdNameMap;
        }
        return new HashMap<>();
    }

    protected FilterMembersParam convert(ExportContext context){
        FilterMembersParam filterMembersParam = new FilterMembersParam();
        filterMembersParam.setOrgId(context.getOrgId());
        filterMembersParam.setSuperRole(context.getSuperRole());
        filterMembersParam.setIsSenior(context.getIsSenior());
        filterMembersParam.setMType(context.getMType());
        filterMembersParam.setMemberIds(context.getFilterMemberIds());
        filterMembersParam.setSearch(context.getSearch());
        filterMembersParam.setCondition(context.getCondition());
        filterMembersParam.setGroupId(context.getGroupId());
        filterMembersParam.setUserId(context.getOpUserId());
        filterMembersParam.setSortBy(context.getSortBy());
        filterMembersParam.setDescending(context.getDescending());
        return filterMembersParam;
    }
}
